#pragma once

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"

const int BACKLOG=5;

class TcpServer
{
  private:
    int _port;
    int listen_sock;
    static TcpServer* svr;

  private:
    TcpServer(int port)
      :_port(port)
       ,listen_sock(-1)
    {}

    TcpServer(const TcpServer& ts)=delete;
    TcpServer& operator=(const TcpServer& ts)=delete;

  public:
    ~TcpServer()
    {
      if(listen_sock>=0)
      {
        close(listen_sock);
      }

    }

    static TcpServer* GetInstance(int port)
    {
      static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
      if(nullptr==svr)
      {
        pthread_mutex_lock(&lock);
        if(nullptr==svr)
        {
          svr=new TcpServer(port);
          svr->InitTcpServer();
        }
        pthread_mutex_unlock(&lock);
      }

      return svr; 
    }

    int Sock()
    {
      return listen_sock;
    }

  private:
    void InitTcpServer()
    {
      Socket();
      Bind();
      Listen();

      LOG(INFO,"tcp init succeess");
    }

    void Socket()
    {
      listen_sock=socket(AF_INET,SOCK_STREAM,0);
      if(listen_sock<0)
      {
        LOG(FATAL,"create socket fail");
        exit(2);
      }

      //端口复用
      int opt=1;
      setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
      LOG(INFO,"create socket success");
    }

    void Bind()
    {
      struct sockaddr_in local;
      memset(&local,0,sizeof(local));
      local.sin_family=AF_INET;
      local.sin_port=htons(_port);
      local.sin_addr.s_addr=INADDR_ANY;

      if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
        LOG(FATAL,"bind socket fail");
        exit(3);
      }
      LOG(INFO,"bind socket fail");
    }

    void Listen()
    {
      if(listen(listen_sock,BACKLOG)<0)
      {
        LOG(FATAL,"listen socket fail");
      }
      LOG(INFO,"listen socket success");
    }
};
TcpServer* TcpServer::svr=nullptr;
